package main
import (
	"fmt"
	"reflect"
)
/*
要求如下：《作业》
1、编写一个cal结构体，有两个字段Num1和Num2
2、方法GetSub(name string)
3、使用反射机制遍历Call结构体所有的字段信息
4、使用反射机制完成对GetSub的调用，输出形式为“tom完成了减法运算，8-5=3”
*/
func main(){
	var cal *Cal = &Cal{}
	fmt.Println("Cal:",cal)
	fmt.Println()

	ReflectCalStruct(cal)

	fmt.Println()	
	fmt.Println("Cal:",cal)	
	
}

type Cal struct{
	Num1 int `json:"num1"`
	Num2 int `json:"num2"`
}
func (c Cal)GetSub(name string){
	fmt.Printf("%s 完成了减法运算 ，%v - %v = %v\n",name,c.Num1,c.Num2,(c.Num1-c.Num2))
}

func ReflectCalStruct(a interface{}){
	typ := reflect.TypeOf(a) //获取持有值为 *Cal 的 Type类型
	val := reflect.ValueOf(a) //获取持有值为 *Cal 的 Value类型
	fmt.Printf("typ : %v ---- val : %v\n",typ,val)
	fmt.Printf("typ.Kind : %v ---- typ.Elem.Kind : %v\n",typ.Kind().String(),typ.Elem().Kind().String())
	//获取结构体中的字段数量
	numField := val.Elem().NumField()
	fmt.Printf("this struct has %d fields\n",numField)
	//遍历结构体所有字段信息
	for i:=0;i< numField;i++{
		eval := val.Elem().Field(i)
		etyp := typ.Elem().Field(i)
		fmt.Printf("The No.%d Field is type(%v) value(%v) and it's tag is `%v`\n",i,eval.Kind().String(),eval.Int(),etyp.Tag.Get("json"))
	}
	//给字段重新赋值
	val.Elem().Field(0).SetInt(8)
	val.Elem().Field(1).SetInt(5)
	//获取结构体所持方法数量
	numMethod := val.Elem().NumMethod()
	fmt.Printf("This struct has %d methods\n",numMethod)
	//准备好方法所需参数的[]Value
	var inValue []reflect.Value
	inValue = append(inValue,reflect.ValueOf("tom"))
	//调用第一个方法并传入参数
	val.Elem().Method(0).Call(inValue)
}

/*运行结果
Cal: &{0 0}

typ : *main.Cal ---- val : &{0 0}
typ.Kind : ptr ---- typ.Elem.Kind : struct
this struct has 2 fields
The No.0 Field is type(int) value(0) and it's tag is `num1`
The No.1 Field is type(int) value(0) and it's tag is `num2`
This struct has 1 methods
tom 完成了减法运算 ，8 - 5 = 3

Cal: &{8 5}
*/